package com.gavin.utils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

//import org.apache.log4j.Logger;
import com.gavin.DBTrans;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gavin.model.Model;
import com.gavin.model.Page;

/**
 * ------------------------------
 * Injector
 * ------------------------------
 * @author wdm  @date 2017年12月28日
 * @version 1.0
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Injector {
	private static Logger logger=LoggerFactory.getLogger(Injector.class);
	
	private static <M> M createInstance(Class<M> objClass) {
		try {
			return objClass.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	
	public static final <M> M injectPage(Class<M> beanClass, Model request, boolean skipConvertError) {
		if(request.empty()){
			return null;
		}
		setTotalPage(request);
		Page page=new Page();
		page.setPageNumber(request.getLong("pageNumber")+ DBTrans.defaultPageNumber);
		page.setPageSize(request.getLong("pageSize"));
		page.setTotalCount(request.getLong("totalCount"));
		page.setTotalPage(request.getLong("totalPage"));
		
		Model[] dms=request.getModels("list");
		List<M> list=new ArrayList<M>();
		Method[] methods = beanClass.getMethods();
		for (int i = 0; i < dms.length; i++) {
			Object bean = createInstance(beanClass);
			Model dm=dms[i];
			
			for (Method method : methods) {
				String methodName = method.getName();
				if (methodName.startsWith("set") == false || methodName.length() <= 3) {	// only setter method
					continue;
				}
				Class<?>[] types = method.getParameterTypes();
				if (types.length != 1) {						// only one parameter
					continue;
				}
				
				String attrName = firstCharToLowerCase(methodName.substring(3));
				if (dm.exists(attrName)) {
					try {
						if(types[0] == java.util.Date.class){
							method.invoke(bean, DateUtils.string2Date(dm.getString(attrName)));
						}else{
							method.invoke(bean, dm.get(attrName));
						}
					} catch (Exception e) {
						logger.error("Injector error!!!:"+e.getMessage() + " ,with  attrName["+attrName+"]");
						if (skipConvertError == false) {
							throw new RuntimeException(e);
						}
					}
				}
			}
			
			list.add((M) bean);
		}
		page.setList(list);
		return (M) page;
	}
	
	public static final <M> M injectBean(Class<M> beanClass,String transAttrName, Model model, boolean skipConvertError) {
		Model temp=model;
		
		 if(transAttrName!=null){
				if(model.exists(transAttrName)){
					temp=model.getModel(transAttrName);
				}else{
					return null;
				}
		}
		if(temp==null || temp.empty()){
			return null;
		}
		
		Method[] methods = beanClass.getMethods();
		Object bean = createInstance(beanClass);
		for (Method method : methods) {
			String methodName = method.getName();
			if (methodName.startsWith("set") == false || methodName.length() <= 3) {	// only setter method
				continue;
			}
			Class<?>[] types = method.getParameterTypes();
			if (types.length != 1) {						// only one parameter
				continue;
			}
			
			String attrName = firstCharToLowerCase(methodName.substring(3));
			if (temp.exists(attrName)) {
				try {
					if(types[0] == java.util.Date.class){
						method.invoke(bean, DateUtils.string2Date(temp.getString(attrName)));
					}else{
						method.invoke(bean, temp.get(attrName));
					}
				} catch (Exception e) {
					logger.error("Injector error!!!:"+e.getMessage() + " ,with  attrName["+attrName+"]");
					if (skipConvertError == false) {
						throw new RuntimeException(e);
					}
				}
			}
		}
		return (M) bean;
	}
	
	public static final <M> M injectBean(Class<M> beanClass, Model model, boolean skipConvertError) {
		return injectBean(beanClass, null,  model,  skipConvertError);
	}
	
//	public static final Pages page(Model request, boolean skipConvertError) {
//		if(request.empty() || !request.exists("list")){
//			return new Pages();
//		}
//		setTotalPage(request);
//		Pages page=new Pages();
//		page.setPageNumber(request.getLong("pageNumber"));
//		page.setPageSize(request.getLong("pageSize"));
//		page.setTotalCount(request.getLong("totalCount"));
//		page.setTotalPage(request.getLong("totalPage"));
//		
//		Model[] dms=request.getModels("list");
//		List<String> list=new ArrayList<String>();
//		for (int i = 0; i < dms.length; i++) {
//			Model dm=dms[i];
//			list.add(dm.toJson());
//		}
//		page.setList(list);
//		return page;
//	}
	
	public static final <M> List<M> injectList(Class<M> beanClass, Model request, boolean skipConvertError) {
		return injectList(beanClass,"list", request, skipConvertError);
	}
	
	public static final <M> List<M> injectList(Class<M> beanClass, String transAttrName,Model request, boolean skipConvertError) {
		if(!request.exists(transAttrName)){
			return new ArrayList<M>();
		}
		Model[] dms=request.getModels(transAttrName);
		List<M> list=new ArrayList<M>();
		Method[] methods = beanClass.getMethods();
		for (int i = 0; i < dms.length; i++) {
			Object bean = createInstance(beanClass);
			Model dm=dms[i];
			
			for (Method method : methods) {
				String methodName = method.getName();
				if (methodName.startsWith("set") == false || methodName.length() <= 3) {	// only setter method
					continue;
				}
				Class<?>[] types = method.getParameterTypes();
				if (types.length != 1) {						// only one parameter
					continue;
				}
				
				String attrName = firstCharToLowerCase(methodName.substring(3));
				if (dm.exists(attrName)) {
					try {
						if(types[0] == java.util.Date.class){
							method.invoke(bean, DateUtils.string2Date(dm.getString(attrName)));
						}else{
							method.invoke(bean, dm.get(attrName));
						}
					} catch (Exception e) {
						logger.error("Injector error!!!:"+e.getMessage() + " ,with  attrName["+attrName+"]");
						if (skipConvertError == false) {
							throw new RuntimeException(e);
						}
					}
				}
			}
			
			list.add((M) bean);
		}
		return list;
	}
	
	public static String firstCharToLowerCase(String value){
		value=(value.substring(0,1)).toLowerCase()+value.substring(1);
		return value;
	}
	
	public static void setTotalPage(Model dm) {
		Long totalCount=dm.getLong("totalCount");
		Long pageSize=dm.getLong("pageSize");
		if(totalCount==null || pageSize==null){
			dm.set("totalPage", 0L);
			return;
		}
		int totalPage = (int) (totalCount / pageSize);
		if (totalCount % pageSize != 0) {
			totalPage++;
		}
		dm.set("totalPage", totalPage);
	}
}

